# coding=utf-8
import time
import uuid
import json
import enum
from django.db.models.query import QuerySet
from .fields import *
from django.core.paginator import Paginator, EmptyPage
from django.core.exceptions import FieldDoesNotExist

__author__ = 'Maple.Liu'

SOFT_DELETE_FIELD_NAME = 'deleted_at'


def get_uuid_str():
    """
    获取UUID的字符串
    :return:
    """
    return uuid.uuid4().hex


def get_time_stamp():
    """
    获取整型时间戳
    :return:
    """
    return time.time()


class ModelManager(raw_models.Manager):
    def get_queryset(self):
        """
        自定义过滤QuerySet
        :return:
        """
        if SOFT_DELETE_FIELD_NAME in [e.name for e in self.model._meta.fields]:
            return QuerySet(self.model, using=self._db).filter(**{SOFT_DELETE_FIELD_NAME: 0})
        else:
            return QuerySet(self.model, using=self._db)

    def filter_by_page(self, offset=-1, limit=-1, order=None, q_params=None, *args, **kwargs):
        """Filter By Page"""
        if q_params is None:
            qs = self.get_queryset().filter(*args, **kwargs)
        else:
            qs = self.get_queryset().filter(q_params, *args, **kwargs)
        if order is not None:
            qs = qs.order_by(order)
        count = qs.count()
        if offset == -1 and limit == -1:
            return count, qs
        else:
            paginator = Paginator(qs, limit)
            req_page = offset // limit + 1
            try:
                return count, paginator.page(req_page).object_list
            except EmptyPage:
                return 0, []


class Model(raw_models.Model):
    class Meta:
        abstract = True
        ordering = ('-add_timestamp', )

    export_fields = []

    # 使用自扩展Manager
    objects = ModelManager()

    # 时间日期格式
    datetime_format = '%Y-%m-%d %H:%M:%S'

    # Properties
    properties = [
        {
            'field_name': 'get_add_time',
            'field_label': '入库时间',
        }
    ]

    # Ignore Fields
    ignore_fields = ['add_timestamp', 'update_timestamp', 'deleted_at']

    secret_fields = ['password']

    # 初始化
    init_data = []

    # 公共字段
    id = CharField(verbose_name=u'UUID', max_length=32, default=get_uuid_str, editable=False, primary_key=True)
    add_timestamp = FloatField(verbose_name=u'入库时间', default=get_time_stamp)
    update_timestamp = FloatField(verbose_name=u'更新时间', default=get_time_stamp)
    deleted_at = FloatField(verbose_name=u'删除时间（是否已删除）', default=0)

    @classmethod
    def get_output_fields(cls):
        return [f.name for f in cls._meta.fields] + ['get_add_time', 'get_update_time']

    @classmethod
    def get_secret_fields(cls):
        return cls.secret_fields

    @classmethod
    def get_ignore_fields(cls):
        return cls.ignore_fields

    def as_dict(self, keys=None, exclude_keys=None):
        """
        将ORM对象序列化为字典
        :param keys:
        :return:
        """
        if not keys:
            keys = self.output_fields
        keys += ['add_timestamp', 'update_timestamp', 'id']
        keys = set(keys)
        object_dict = dict()
        for key in keys:
            if exclude_keys and key in exclude_keys:
                continue
            value = last_value = getattr(self, key)
            if isinstance(value, raw_models.Model):
                if isinstance(value, self.__class__):
                    last_value = value.__str__()
                else:
                    last_value = value.as_dict()
            if last_value is None:
                last_value = ''
            object_dict[key] = last_value
            try:
                key_field = self.__class__._meta.get_field(key)
            except FieldDoesNotExist:
                continue
            if key_field.choices:  # 如果是下拉列表字段
                object_dict[key + '_map'] = dict(key_field.choices)
        return object_dict

    def as_json(self, keys=None):
        """
        JSON序列化
        :param keys:
        :return:
        """
        return json.dumps(self.as_dict(keys))

    def get_add_time(self):
        """
        从ORM对象时间戳转换为字符串时间格式
        :return:
        """
        return time.strftime(self.datetime_format, time.localtime(self.add_timestamp))

    get_add_time.allow_tags = True
    get_add_time.short_description = u'添加时间'

    def get_update_time(self):
        """
        从ORM对象时间戳转换为字符串时间格式
        :return:
        """
        return time.strftime(self.datetime_format, time.localtime(self.update_timestamp))

    get_update_time.allow_tags = True
    get_update_time.short_description = u'更新时间'

    def soft_delete(self):
        """
        对象软删除，只更新删除标记 is_deleted 为 True
        :return: ObjectId
        """
        self.deleted_at = int(time.time())
        self.save()
        return self.pk

    @staticmethod
    def batch_soft_delete(objects):
        """
        批量对象软删除，只更新删除标记 deleted_at
        :return: objects
        """
        objects.update(deleted_at = int(time.time()))
        return objects

    def update(self, **data):
        """
        修改
        """
        field_keys = [f.name for f in self.__class__._meta.get_fields()]

        for k, v in data.items():
            if k in field_keys:
                setattr(self, k, v)
        self.update_timestamp = int(time.time())
        self.save()
        return self

    @classmethod
    def get_fields_verbose_names(cls, fields=None):
        all_fields_map = {f.name: f for f in cls._meta.fields}
        if fields is None:
            return {k: v.verbose_name for k,v in all_fields_map.items()}
        labels = []
        for field in fields:
            labels.append(all_fields_map[field].verbose_name)
        return labels

    @classmethod
    def get_fields_names(cls, fields=None):
        all_fields_map = {f.name: f for f in cls._meta.fields}
        if fields is None:
            return [v.name for k,v in all_fields_map.items()]
        names = []
        for field in fields:
            names.append(all_fields_map[field].name)
        return names

    @classmethod
    def make_choices(cls, *args, **kwargs):
        objs = cls.objects.filter(*args, **kwargs)
        return [(obj.id, obj.__str__()) for obj in objs]

    @classmethod
    def make_choices_by_page(cls, offset=-1, limit=-1, *args, **kwargs):
        count, objs = cls.objects.filter_by_page(offset=offset, limit=limit, *args, **kwargs)
        return [(obj.id, obj.__str__()) for obj in objs]

    def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):
        self.update_timestamp = time.time()
        super().save(force_insert, force_update, using, update_fields)

class Choices(enum.Enum):
    """
    Choices生成器
    """

    @classmethod
    def get_choices(cls):
        """
        从枚举类生成django-field-choices
        :return:
        """
        return tuple([(k, e.value) for k, e in cls.__members__.items()])

    @classmethod
    def get_key_name_by_value(cls, value):
        choices = cls.get_choices()
        for k, v in choices:
            if v == value:
                return k


class BusinessModel(object):
    """
    Business Model
    """
    pass
